#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <UIKit/UIApplication.h>
#import <LockInfo/Plugin.h>

#import "framework/FWCommon.h"
#import "framework/FWDetailListEntry.h"
#import "framework/FWDetailListSection.h"
#import "framework/FWPopupView.h"
#import "framework/FWColorIconView.h"
#import "framework/FWMapView.h"

#import "PICommon.h"
#import "PIEventPlugin.h"
#import "PIEventStatus.h"
#import "PIEventPreview.h"
#import "PIContextObject.h"
#import "PIEventListAccess.h"
#import "PIIntegration.h"
#import "PIAttendee.h"

#import "PIEventIntegration.h"
#import "PIEventNative.h"
#import "PIEvent.h"


static NSDictionary* attendeeStatusLookup = [[NSDictionary alloc] initWithObjectsAndKeys:
                                             @"Participant/Pending", FWNewNumberWithInt(kPIParticipantStatusPending),
                                             @"Participant/Accepted", FWNewNumberWithInt(kPIParticipantStatusAccepted),
                                             @"Participant/Declined", FWNewNumberWithInt(kPIParticipantStatusDeclined),
                                             @"Participant/Tentative", FWNewNumberWithInt(kPIParticipantStatusTentative),
                                             @"Participant/Delegated", FWNewNumberWithInt(kPIParticipantStatusDelegated),
                                             @"Participant/Completed", FWNewNumberWithInt(kPIParticipantStatusCompleted),
                                             @"Participant/InProcess", FWNewNumberWithInt(kPIParticipantStatusInProgress),
                                             @"Participant/Unknown", FWNewNumberWithInt(kPIParticipantStatusUnknown),
                                             nil];

static NSDictionary* availabilityLookup = [[NSDictionary alloc] initWithObjectsAndKeys:
                                           @"Availability/Free", FWNewNumberWithInt(kPIEventAvailabilityFree),
                                           @"Availability/Busy", FWNewNumberWithInt(kPIEventAvailabilityBusy),
                                           @"Availability/Out of Office", FWNewNumberWithInt(kPIEventAvailabilityOutOfOffice),
                                           @"Availability/Tentative", FWNewNumberWithInt(kPIEventAvailabilityTentative),
                                           @"Availability/Unavailable", FWNewNumberWithInt(kPIEventAvailabilityUnavailable),
                                           nil];

static NSDictionary* availabilityIconLookup = [[NSDictionary alloc] initWithObjectsAndKeys:
                                               @"busy", FWNewNumberWithInt(kPIEventAvailabilityBusy),
                                               @"outofoffice", FWNewNumberWithInt(kPIEventAvailabilityOutOfOffice),
                                               @"tentative", FWNewNumberWithInt(kPIEventAvailabilityTentative),
                                               @"unavailable", FWNewNumberWithInt(kPIEventAvailabilityUnavailable),
                                               nil];

static NSDictionary* statusLookup = [[NSDictionary alloc] initWithObjectsAndKeys:
                                     @"Status/None", FWNewNumberWithInt(PIEventStatusTypeNone),
                                     @"Status/Cancelled", FWNewNumberWithInt(PIEventStatusTypeCancelled),
                                     @"Status/Confirmed", FWNewNumberWithInt(PIEventStatusTypeConfirmed),
                                     @"Status/Tentative", FWNewNumberWithInt(PIEventStatusTypeTentative),
                                     nil];


static NSString* const kUsersPage = @"-1";
static NSString* const kTagsPage = @"-2";
static NSString* const kLocationNumbersPage = @"-3";
static NSString* const kNotesNumbersPage = @"-4";
static NSString* const kNotesPage = @"-5";
static NSString* const kMapPage = @"-6";


@implementation PIEventPreview

@synthesize detailPageID, currentEvent, currentApplication;


- (id)initWithApplication:(FWApplication*)application
{
    if ((self = [super init])) {
        self.currentApplication = application;
    }
    
    return self;
}

- (void)dealloc
{
    [detailPageID release];
    [currentEvent release];
    [currentApplication release];
    
    [super dealloc];
}

- (PIEvent*)augmentEvent:(PIEvent*)event application:(FWApplication*)application
{
    if (event.isNative)
        return [PIEventNative augmentedBasicEvent:event application:application];
    else
        return [PIEventIntegration augmentedBasicEvent:event application:application];
}


// ******************************************************************************************
#pragma mark -
#pragma mark General view support

- (NSArray*)dataForUserListPage:(NSObject*)page application:(FWApplication *)application item:(PIEvent*)event values:(NSDictionary*)values
{
    NSBundle* bundle = [NSBundle bundleForClass:[self class]];
    
    event = [self augmentEvent:event application:application];

    NSMutableArray* userEntries = [NSMutableArray arrayWithCapacity:event.attendees.count];
    
    for (PIAttendee* attendee in event.attendees) {
        NSString* status = [attendeeStatusLookup objectForKey:[NSNumber numberWithInt:attendee.status]];
        if (!status)
            status = [attendeeStatusLookup objectForKey:[NSNumber numberWithInt:kPIParticipantStatusUnknown]];
        if (attendee.status == kPIParticipantStatusUnknown)
            status = @"";
        [userEntries addObject:[FWDetailListEntry entryWithTitle:attendee.name value:localize(bundle, status)]];
    }
    
    return [NSArray arrayWithObject:[FWDetailListSection sectionForElements:userEntries]];
}

- (NSArray*)dataForTagsListPage:(NSObject*)page application:(FWApplication *)application item:(PIEvent*)event values:(NSDictionary*)values
{
    event = [self augmentEvent:event application:application];
    
    NSMutableArray* tagEntries = [NSMutableArray arrayWithCapacity:event.tags.count];

    NSMutableArray* tags = [NSMutableArray arrayWithArray:event.tags];
    [tags sortUsingFunction:compareContextObjectNames context:nil];
    
    for (PIContextObject* tag in tags) {
        [tagEntries addObject:
         [super detailColourEntryForTitle:tag.name
                                    value:nil
                                     icon:tag.icon
                             calendarIcon:nil
                            calendarColor:tag.color]];
    }
    
    return [NSArray arrayWithObject:[FWDetailListSection sectionForElements:tagEntries]];
}

- (NSArray*)dataForEventDetailPage:(NSObject*)page application:(FWApplication *)application item:(PIEvent*)item1 values:(NSDictionary*)values
{
    NSBundle* bundle = [NSBundle bundleForClass:[self class]];
    PIEvent* event = [self augmentEvent:(PIEvent*)item1 application:application];

    XLog(@"LI:PIEvent: Displaying detail of event %@", event);
    
    NSString* platform = FWGetPlatformType();
    BOOL hasRadio = platform && [platform isEqualToString:@"iPhone"];
    
#ifdef DEVELOPMENT_MODE
    hasRadio = YES;
#endif

    XLog(@"LI:PIEvent: Platorm type = %@; radio = %d", platform, hasRadio);

    // Sections to use
    NSMutableArray* titleSect = [NSMutableArray arrayWithCapacity:3];
    NSMutableArray* datesSect = [NSMutableArray arrayWithCapacity:3];
    NSMutableArray* debugDatesSect = [NSMutableArray arrayWithCapacity:5];
    NSMutableArray* progressSect = [NSMutableArray arrayWithCapacity:3];
    NSMutableArray* contextSect = [NSMutableArray arrayWithCapacity:3];
    NSMutableArray* peopleSect = [NSMutableArray arrayWithCapacity:2];
    NSMutableArray* notesSect = [NSMutableArray arrayWithCapacity:3];

    // Header information
    FWDetailListEntry* titleEntry = [[FWDetailListEntry entryWithTitle:[PIIntegration stringForTitle:event.title
                                                                                            withIcon:event.icon 
                                                                                     withProjectIcon:nil]]
                                     withSize:[FWDetailListEntry fontSizeForTitle]];
    [titleSect addObject:titleEntry];
    if (event.location && (event.location.length > 0)) {
        FWDetailListEntry* locationEntry = [FWDetailListEntry entryWithTitle:event.location];

        if (event.coordinates || (event.location.length < 80)) {
            locationEntry.link = YES;
            locationEntry.key = kMapPage;
            locationEntry.icon = [UIImage imageWithContentsOfFile:[bundle pathForResource:@"map" ofType:@"png"]];
        }

        [titleSect addObject:locationEntry];

        if (hasRadio && [self numbersFromString:event.location]) {
            [titleSect addObject:
             [[[FWDetailListEntry entryWithLocalisedTitle:@"Detail/Numbers"
#ifdef DEVELOPMENT_MODE
                                                    value:kNotesNumbersPage
#endif
                                                   bundle:bundle]
               withIconFile:[bundle pathForResource:@"phone" ofType:@"png"]]
              withLinkType:kLocationNumbersPage]];
        }
    }
    
    
    // Dates section
    NSDate* now = [NSDate date];
    
    NSDate* start = event.rangeStartDate;
    if (start.isNull)
        start = event.startDate;
    if (!start.isNull) {
        [datesSect addObject:
         [FWDetailListEntry entryWithLocalisedTitle:[start isLaterThanDate:now] ? @"Detail/Starts" : @"Detail/Started"
                                              value:FWLocalDateStringForUTCDate(start, FWDateFormatterLongFormat, !event.isAllDay, bundle)
                                             bundle:bundle]];

        if (application.fwPlugin.isDebugMode) {
            [debugDatesSect addObject:
             [FWDetailListEntry entryWithTitle:@"Starts"
                                         value:[NSString stringWithFormat:@"%@", start]]];
            [debugDatesSect addObject:
             [FWDetailListEntry entryWithTitle:@"-SRaw"
                                         value:[[NSDate dateWithTimeIntervalSinceReferenceDate:event.startDateRaw] description]]];
        }
    }
    
    NSDate* endDate = event.rangeEndDate;
    if (endDate.isNull)
        endDate = event.endDate;
    if (!endDate.isNull) {
        FWDateFormatterFormat format = FWIsLocalDateSameDay(start, endDate) ? FWDateFormatterTimeOnlyFormat : FWDateFormatterLongFormat;
        
        if (event.isAllDay || [start compare:endDate] != 0) {
            [datesSect addObject:
             [FWDetailListEntry entryWithLocalisedTitle:[endDate isLaterThanDate:now] ? @"Detail/Ends" : @"Detail/Ended"
                                                  value:format == FWDateFormatterTimeOnlyFormat && event.isAllDay ? localize(bundle, @"Detail/All Day") : FWLocalDateStringForUTCDate(endDate, format, !event.isAllDay, bundle)
                                                 bundle:bundle]];
        }

        if (application.fwPlugin.isDebugMode) {
            [debugDatesSect addObject:
             [FWDetailListEntry entryWithTitle:@"Ends"
                                         value:[NSString stringWithFormat:@"%@", endDate]]];
            [debugDatesSect addObject:
             [FWDetailListEntry entryWithTitle:@"-ERaw"
                                         value:[[NSDate dateWithTimeIntervalSinceReferenceDate:event.endDateRaw] description]]];
        }
    }
    
    if (application.fwPlugin.isDebugMode) {
        [debugDatesSect addObject:
         [FWDetailListEntry entryWithTitle:@"Now"
                                     value:[[NSDate date] description]]];
        
        [debugDatesSect addObject:
         [FWDetailListEntry entryWithTitle:@"Alarm1"
                                     value:[event.firstAlarm description]]];
        [debugDatesSect addObject:
         [FWDetailListEntry entryWithTitle:@"+Next"
                                     value:[event.nextAlarm description]]];
    }

    if (event.isInvitation) {
        [progressSect addObject:
         [FWDetailListEntry entryWithLocalisedTitle:@"Detail/Status"
                                     localisedValue:@"Status/Invitation"
                                             bundle:bundle]];
    }
    else if (event.status == PIEventStatusTypeNone) {
        // Don't dispay
    }
    else if (NSString* statusDesc = [statusLookup objectForKey:[NSNumber numberWithInt:event.status]]) {
        [progressSect addObject:
         [FWDetailListEntry entryWithLocalisedTitle:@"Detail/Status"
                                     localisedValue:statusDesc
                                             bundle:bundle]];
    }
    
    if (event.availability != kPIEventAvailabilityNotSupported) {
        if (NSString* availDesc = [availabilityLookup objectForKey:[NSNumber numberWithInt:event.availability]]) {
            FWColorIconView* availIcon = nil;
            if (NSString* icon = [availabilityIconLookup objectForKey:[NSNumber numberWithInt:event.availability]]) {
                availIcon = [[[FWColorIconView alloc] initWithFrame:CGRectMake(0, 0,  16, 16)] autorelease];
                availIcon.icon = [bundle pathForResource:icon ofType:@"png"];
            }

            [progressSect addObject:
             [[FWDetailListEntry entryWithLocalisedTitle:@"Detail/Availability"
                                          localisedValue:availDesc
                                                  bundle:bundle]
              withColorAccessoryView:availIcon]];
        }
    }

    // Alarms section
    NSArray* alarmsSect = [super alarmsListForObject:event dueDate:event.startDate bundle:bundle application:application];

    
    // People section
    if (event.organiser) {
        [peopleSect addObject:
         [FWDetailListEntry entryWithLocalisedTitle:@"Detail/Initiator"
                                              value:event.organiser
                                             bundle:bundle]];
    }
    
    if (event.hasAttendees) {
        NSMutableString* attendees = [NSMutableString stringWithCapacity:50];
        for (PIAttendee* attendee in event.attendees) {
            [attendees appendString:attendee.name withSeparator:@", "];
        }
        
        [peopleSect addObject:
         [[FWDetailListEntry entryWithLocalisedTitle:@"Detail/Attendees"
                                               value:attendees
                                              bundle:bundle]
          withLinkType:kUsersPage]];
    }

    
    // Repeat info
    NSArray* repeatSect = [super repeatSectionForObject:event bundle:bundle application:application];


    // Context section
#ifdef DEBUG
//    [contextSect addObject:
//     [FWDetailListEntry entryWithTitle:@"ID"
//                                 value:event.key]];
#endif

    NSMutableArray* sensitivitySect = [NSMutableArray arrayWithCapacity:1];
    if (event.sensitivity != PISensitivityTypeNone)
        [sensitivitySect addObject:[self entryForSensitivity:event.sensitivity bundle:bundle]];
    
    if (event.calendar) {
        [contextSect addObject:
         [super detailColourEntryForTitle:localize(bundle, event.isNative ? @"Detail/Calendar/iOS" : @"Detail/Calendar/PI")
                                    value:event.calendar
                                     icon:nil
                             calendarIcon:event.calendarIcon
                            calendarColor:event.calendarColor]];
    }
    
    if (event.tags) {
        FWDetailListEntry* entry = [FWDetailListEntry entryWithLocalisedTitle:@"Detail/Tags"
                                                                        value:[event.tags piContextObjectString]
                                                                       bundle:bundle];
        
        if (event.tags.count > 1)
            [entry withLinkType:kTagsPage];

        [contextSect addObject:entry];
    }

    if (NSString* notes = event.notesSummary) {
        if ([[notes stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] > 0) {
            if (notes.length != event.notes.length) {
                [notesSect addObject:
                 [[[FWDetailListEntry entryWithTitle:notes]
                   withSize:kFWDetailListViewSystemFontSize]
                  withNoBold]];
                
                [notesSect addObject:
                 [[[FWDetailListEntry entryWithLocalisedTitle:@"Detail/Show Notes"
#ifdef DEVELOPMENT_MODE
                                                        value:kNotesPage
#endif
                                                       bundle:bundle]
                   withIconFile:[bundle pathForResource:@"notes" ofType:@"png"]]
                  withLinkType:kNotesPage]];
            }
            else {
                [notesSect addObject:
                 [[[FWDetailListEntry entryWithTitle:notes]
                   withSize:kFWDetailListViewSystemFontSize]
                  withNoBold]];
            }
            
            if (hasRadio && [self numbersFromString:event.notes])
                [notesSect addObject:
                 [[[FWDetailListEntry entryWithLocalisedTitle:@"Detail/Numbers"
#ifdef DEVELOPMENT_MODE
                                                        value:kNotesNumbersPage
#endif
                                                       bundle:bundle]
                   withIconFile:[bundle pathForResource:@"phone" ofType:@"png"]]
                  withLinkType:kNotesNumbersPage]];
        }    
    }    
    
    // Build sections list
    NSMutableArray* sects = [NSMutableArray arrayWithCapacity:8];
    [sects addObject:[[FWDetailListSection sectionForElements:titleSect] withExtraSeparatorSpace:kFWDetailListViewExtraHeaderSpace]];
    if ([datesSect count] > 0)
        [sects addObject:[FWDetailListSection sectionForElements:datesSect]];
    if ([progressSect count] > 0)
        [sects addObject:[FWDetailListSection sectionForElements:progressSect]];
    if ([sensitivitySect count] > 0)
        [sects addObject:[FWDetailListSection sectionForElements:sensitivitySect]];
    if ([contextSect count] > 0)
        [sects addObject:[FWDetailListSection sectionForElements:contextSect]];
    if ([peopleSect count] > 0)
        [sects addObject:[FWDetailListSection sectionForElements:peopleSect]];
    if ([repeatSect count] > 0)
        [sects addObject:[FWDetailListSection sectionForElements:repeatSect]];
    if ([alarmsSect count] > 0)
        [sects addObject:[FWDetailListSection sectionForElements:alarmsSect]];
    if ([notesSect count] > 0)
        [sects addObject:[FWDetailListSection sectionForElements:notesSect
                                                       withTitle:localize(bundle, @"Detail/Notes")]];
    if ([debugDatesSect count] > 0)
        [sects addObject:[FWDetailListSection sectionForElements:debugDatesSect
                                                       withTitle:@"Event Date Values"]];

    return sects;
}

- (NSArray*)dataForDetailListPage:(NSObject*)page key:(NSObject*)key application:(FWApplication *)application
{
    PIEvent* elem = (PIEvent*)page;

    if ([self.detailPageID isEqualToString:kUsersPage])
        return [self dataForUserListPage:page application:application item:elem values:nil];
    else if ([self.detailPageID isEqualToString:kLocationNumbersPage])
        return [self dataForNumberListPage:elem application:application string:elem.location prompt:elem.location];
    else if ([self.detailPageID isEqualToString:kNotesNumbersPage]) {
        PIEvent* augment = [self augmentEvent:elem application:application];
        return [self dataForNumberListPage:elem application:application string:augment.notes prompt:nil];
    }
    else if ([self.detailPageID isEqualToString:kTagsPage])
        return [self dataForTagsListPage:page application:application item:elem values:nil];
    else
        return [self dataForEventDetailPage:page application:application item:elem values:nil];
}

- (NSString*)listPagePopupForKey:(NSObject *)key currentPage:(NSObject *)page displayDepth:(NSInteger)depth application:(FWApplication *)application
{
    PIEventStatus* status = (PIEventStatus*)application.info;

    if ([(NSString*)key isEqualToString:kLocationNumbersPage] || [(NSString*)key isEqualToString:kNotesNumbersPage]) {
        if (!status.hasShownDialHelp) {
            status.shownDialHelp = YES;
            return localize([NSBundle bundleForClass:[self class]], @"Detail/Dialer/Help");    
        }
    }
    
    return nil;
}

- (NSString*)listPageTextForKey:(NSObject*)key currentPage:(NSObject*)current displayDepth:(NSInteger)depth application:(FWApplication*)application
{
    if ([(NSString*)key isEqualToString:kNotesPage]) {
        PIEvent* event = [self augmentEvent:(PIEvent*)current application:application];

        if (event.notes)
            return event.notes;
        else
            return @"";
    }
    
    return nil;
}

- (void)willShowBasePage:(NSObject *)page
{
    self.detailPageID = nil;
}

- (NSString*)captionForListPage:(NSObject *)page forKey:(NSObject *)key displayDepth:(NSInteger)depth application:(FWApplication *)application
{
    NSBundle* bundle = [NSBundle bundleForClass:[self class]];
    
    if ([(NSString*)key isEqualToString:kNotesPage])
        return localize(bundle, @"Detail/Notes");
    else if ([(NSString*)key isEqualToString:kLocationNumbersPage] || [(NSString*)key isEqualToString:kNotesNumbersPage])
        return localize(bundle, @"Detail/Dialer/Title");
    else if ([(NSString*)key isEqualToString:kTagsPage])
        return localize(bundle, @"Detail/Tags");
    else if ([(NSString*)key isEqualToString:kMapPage])
        return localize(bundle, @"Detail/Map");
    else
        return localize(bundle, @"Detail/Attendees");
}


// ******************************************************************************************
#pragma mark -
#pragma mark Map page support

- (UIView*)listPageViewForKey:(NSObject *)key currentPage:(NSObject *)page displayDepth:(NSInteger)depth rect:(CGRect)rect application:(FWApplication *)application
{
    if ([(NSString*)key isEqualToString:kMapPage]) {

        BOOL popups = [FWPreferences boolValue:kPIOptionsShowPopups
                                   withDefault:kPIOptionsShowPopupsDefault
                                   preferences:application.fwPlugin.liPlugin.preferences];

        PIEvent* event = (PIEvent*)page;
        FWMapView* view = [[[FWMapView alloc] initWithFrame:rect
                                                     config:application.info
                                                     plugin:application.fwPlugin.liPlugin
                                                 showPopups:popups
                                                   location:event.location
                                                      title:event.title
                                                coordinates:event.coordinates] autorelease];
        return view;
    }
    
    return nil;
}

- (NSArray*)listPageInfoForKey:(NSObject*)key currentPage:(NSObject*)current displayDepth:(NSInteger)depth application:(FWApplication*)application
{
    self.detailPageID = (NSString*)key;
    return [NSArray arrayWithObject:current];
}


// ******************************************************************************************
#pragma mark -
#pragma mark Handling user input

-(void)gotoEventClicked:(UIBarButtonItem*)sender
{
    if (currentEvent.isNative)
        [PIEventNative showInApplication:currentEvent application:currentApplication];
}

- (NSArray*)toolbarForDetailListPage:(NSObject *)page key:(NSObject *)key application:(FWApplication *)application
{
    self.currentEvent = nil;
    
    if ([self.detailPageID isEqualToString:kUsersPage] ||
        [self.detailPageID isEqualToString:kLocationNumbersPage] ||
        [self.detailPageID isEqualToString:kNotesNumbersPage] ||
        [self.detailPageID isEqualToString:kTagsPage])
        return nil;
    else {
        PIEvent* event = (PIEvent*)page;
        
        if (event.isNative) {
            self.currentEvent = event;
            NSBundle* bundle = [NSBundle bundleForClass:[self class]];
            
            UIBarButtonItem* gotoNativeBtn = [[[UIBarButtonItem alloc] initWithImage:
                                               [UIImage imageWithContentsOfFile:[bundle pathForResource:@"gonative"
                                                                                                 ofType:@"png"]]
                                                                               style:UIBarButtonItemStylePlain
                                                                              target:self
                                                                              action:@selector(gotoEventClicked:)] autorelease];

            UIBarButtonItem* gotoPIBtn = [[[UIBarButtonItem alloc] initWithImage:
                                           [UIImage imageWithContentsOfFile:[bundle pathForResource:@"gopi"
                                                                                             ofType:@"png"]]
                                                                           style:UIBarButtonItemStylePlain
                                                                          target:self
                                                                          action:@selector(gotoEventClicked:)] autorelease];

            UIBarButtonItem* flexBtn = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
                                                                                      target:nil
                                                                                      action:nil] autorelease];
            UIBarButtonItem* fixBtn = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace
                                                                                      target:nil
                                                                                      action:nil] autorelease];
            fixBtn.width = 20;
            
            return [NSArray arrayWithObjects:flexBtn, gotoNativeBtn,
//                    fixBtn, gotoPIBtn,
                    flexBtn, nil];
        }
    }
    
    return nil;
}

- (BOOL)doneClicked:(FWApplication*)application sections:(NSArray*)sections
{
    return YES;
}

@end

